package com.smartcommunity.entity.facelib;


import cn.hutool.core.util.IdcardUtil;
import cn.hutool.core.util.StrUtil;
import com.smartcommunity.bean.constant.Constant;
import com.smartcommunity.entity.tag.Tag;
import com.smartcommunity.utils.DateUtils;
import com.smartcommunity.utils.RegExUtils;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

import java.io.Serializable;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

@Data
@ApiModel(description = "人脸库人员信息请求参数模型。所有标记\"后端自动填充\"的属性都不需要前端传参。新增人员时，tagList中标签对象仅填充tagId即可。")
public class FaceLibPerson implements Serializable {
    private static final long serialVersionUID = -1L;

    @ApiModelProperty(value = "ID，主键序号，查询和删除时多个编号用英文逗号分隔", name = "id")
    private String id;

    @ApiModelProperty(value = "人员ID，关联实有人口ID,长度<=36", name = "personId")
    private String personId;

    @ApiModelProperty(value = "身份证号，支持两侧模糊查询，长度<=20", name = "idCardNo")
    private String idCardNo;

    @ApiModelProperty(value = "证号类型编码，长度<=4。枚举: 身份证-10,普通护照-14", name = "credentialType")
    private String credentialType;

    @ApiModelProperty(value = "证号类型编码中文, credentialTypeCN")
    private String credentialTypeCN;


    @ApiModelProperty(value = "姓名。支持两侧模糊查询，长度<=32。注意：查询接口中当idCardNo为空时，也可以用于idCardNo的模糊查询", name = "name")
    private String name;

    @ApiModelProperty(value = "性别编码。枚举 - 0:女性 1:男性 2:未知", name = "gender")
    private Integer gender;

    @ApiModelProperty(value = "性别中文")
    private String genderCN;

    @ApiModelProperty(value = "民族，中文字，长度<=20", name = "nation")
    private String nation;

    @ApiModelProperty(value = "名族中文")
    private String nationCN;

    @ApiModelProperty(value = "人脸库编号(单填，不能多个编号用英文逗号分隔)", name = "libId")
    private String libId;

    @ApiModelProperty(value = "籍贯，长度<=180", name = "origin")
    private String origin;

    @ApiModelProperty(value = "电话，长度<=15", name = "telephone")
    private String phone;

    @ApiModelProperty(value = "出生日期，长度<=24", name = "birthDate")
    private String birthDate;

    @ApiModelProperty(value = "标签关系数组，元素长度<=10，数组长度不限。" +
            "=> 标签搜索示例 1 - 多选或查询(至少有一个tagId是2或3的标签关系)：tagList:[{\"tagId\":\"2,3\"}] " +
            "=> 标签搜索示例 2 - 多选且查询(至少有一个tagId是2或3的标签关系，并且必须有tagId是5和6的标签关系)：tagList:[{\"tagId\":\"2,3\"},{\"tagId\":\"5\"},{\"tagId\":\"6\"}]", name = "tagIds")
    private List<FaceLibPersonTag> tagList = new ArrayList();

    @ApiModelProperty(value = "标签实体数组，仅查询接口展示标签实体用。增删改接口忽略该属性", name = "tagEntityList")
    private List<Tag> tagEntityList = new ArrayList();

    @ApiModelProperty(value = "标签字符串，仅excel导出标签实体用。增删改接口忽略该属性", name = "tags")
    private String tags;

    @Deprecated
    @ApiModelProperty(value = "【废弃，Bug-7006】家庭地址(查询时，前缀精确，后缀模糊）,长度<=128", name = "homeAddress")
    private String homeAddress;

    @ApiModelProperty(value = "图片URLs(英文逗号分隔；" +
            "更新前会对该属性做全等校验，通过后再整合addFacePicPaths/deletePicPaths，得出更新后的FaceImageUrl）"
            , name = "faceImageUrl")
    private String faceImageUrl;

//  @ApiModelProperty(value="要删除的图片URLs(仅更新接口可用，英文逗号分隔）。后台也会删除对应的人脸特征记录。",name="deletePicPaths")
//  private String deletePicPaths;

//  @ApiModelProperty(value="要添加的图片URLs(仅更新接口可用，英文逗号分隔）。后台会在features中新增人脸特征记录。",name="addFacePicPaths")
//  private String addFacePicPaths;

    @ApiModelProperty(value = "创建时间，后端自动填充")
    private Timestamp mrowTime;

    @ApiModelProperty(value = "更新时间，后端自动填充")
    private Timestamp updateTime;

    @ApiModelProperty(value = "查询页数，默认1")
    private Integer page = 1;

    @ApiModelProperty(value = "查询页大小，默认10")
    private Integer pageSize = 10;

    @ApiModelProperty(value = "人脸特征集合。仅用与增删改接口。增加的图片会来这里获取特征码以保存到数据库。", name = "features")
    List<FaceLibPersonFeature> features = new ArrayList(2);

    /**
     * 当证件类型为身份证且证件号不为空时，从身份证号中分析出生日期
     *
     * @return 是否拿到了出生日期
     */
    public boolean findBirthDateFromIdCard() {
        return Optional.of(this).map(FaceLibPerson::getIdCardNo)
                .filter(id -> StrUtil.equals(this.getCredentialType(), String.valueOf(Constant.IDCARD_VALUE)) && RegExUtils.isIdCardNo(id))
                .map(IdcardUtil::getBirthDate)
                .map(DateUtils::formatDShort)
                .map(d -> {
                    this.setBirthDate(d);
                    return true;
                }).orElse(false);
    }

    /**
     * 当证件类型为身份证且证件号不为空时，从身份证号中分析性别
     */
    public void findGenderFromIdCard() {
        Optional.of(this)
                .filter(th -> StrUtil.equals(th.getCredentialType(), String.valueOf(Constant.IDCARD_VALUE)))
                .filter(th -> StrUtil.isNotEmpty(th.getIdCardNo()))
                .map(FaceLibPerson::getIdCardNo)
                .filter(RegExUtils::isIdCardNo)
                .map(IdcardUtil::getGenderByIdCard)
                .filter(Objects::nonNull)
                .ifPresent(this::setGender);
    }

    /**
     * 校验证件号。当证件类型为身份证时，做非空和身份证校验。否则，做非空校验。
     *
     * @return 是否通过校验
     */
    public boolean validateIdCardNo() {
        return Optional.of(this)
                .filter(th -> StrUtil.isNotEmpty(th.getIdCardNo()) && StrUtil.isNotEmpty(th.getCredentialType()))
                .map(FaceLibPerson::getIdCardNo)
                .map(id -> !StrUtil.equals(this.getCredentialType(), String.valueOf(Constant.IDCARD_VALUE)) || RegExUtils.isIdCardNo(id))
                .orElse(false);
    }

    /**
     * 校验电话。可空，大陆、香港手机号、固话都可以。
     *
     * @return 是否通过校验
     */
    public boolean validatePhone() {
        return Optional.of(this)
                .map(FaceLibPerson::getPhone)
                .map(p -> StrUtil.isEmpty(p) || RegExUtils.isPhone(p) || RegExUtils.isPhoneStaion(p))
                .orElse(false);
    }

    public String getTags(){
        String tagStr = null;
        if(tagEntityList!=null){
            for(Tag tag:tagEntityList){
                if(tag!=null)
                if(tagStr ==null){
                    tagStr = tag.getTagName();
                }else{
                    tagStr = tagStr + "," + tag.getTagName();
                }
            }
        }
        return tagStr;
    }
}
